﻿///-----------------------------------------------------------------------
/// <copyright file="PeriodsAllocationViewModel.cs" company="FactSet Research Systems, Inc.">
///     Copyright © FactSet Research Systems, Inc.  All rights reserved 2012.
/// </copyright>
/// <author>Jonathan K. Barez</author>
///-----------------------------------------------------------------------

using System.Data;
using System.Transactions;
using System.Windows;

namespace HousholdISv2.ViewModel.Transaction
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Controls;
    using Core;
    using DataRepository;
    using GalaSoft.MvvmLight.Messaging;
    using MVVMCore;
    using MVVMCore.Messaging;
    using MVVMCore.ViewModel;
    using MVVMCore.ViewModel.Details;

    public class PeriodsAllocationViewModel : UpdateableViewModelBase, IHasItemCollection, IPeriodTransaction
    {
        #region Fields

        private Action cancelAction;
        private readonly PeriodsViewModel parent;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="PeriodsAllocationViewModel"/> class.
        /// </summary>
        public PeriodsAllocationViewModel(PeriodsViewModel parent)
        {
            this.parent = parent;
        }

        #endregion Constructors

        #region Events

        #endregion Events

        #region Properties

        public string DisplayName
        {
            get { return "Allocation"; }
        }

        public bool IsSelected
        {
            get { return GetValue(() => IsSelected); }
            set { SetValue(() => IsSelected, value); }
        }

        public bool IsInSelectionMode
        {
            get { return GetValue(() => this.IsInSelectionMode, true); }
            set
            {
                SetValue(() => this.IsInSelectionMode, value);
                this.parent.RaisePropertyChangedEvent(() => parent.IsInSelectionMode);
                var selected = this.Allocations.SelectedItem;
                if (selected == null)
                {
                    return;
                }

                selected.RaisePropertyChangedEvent(() => selected.InputVisibility);
                selected.RaisePropertyChangedEvent(() => selected.DisplayVisibility);
            }
        }

        public PeriodsAllocationListViewViewModel Allocations
        {
            get { return GetValue(() => this.Allocations) ?? this.InitializeAllocation(); }
            set { SetValue(() => this.Allocations, value); }
        }

        protected override bool CanEdit
        {
            get { return true; }
        }

        protected override bool CanDelete
        {
            get { return this.Allocations.SelectedItem != null; }
        }

        protected override bool CanSave
        {
            get { return this.Allocations.CanSave; } 
        }

        private CommandViewModel CopyCommand
        {
            get { return this.GetValue(() => this.CopyCommand) ?? this.InitializeCopyCommand(); }
            set { this.SetValue(() => this.CopyCommand, value); }
        }

        #endregion Properties

        #region Methods

        public void Load(Period period)
        {
            this.Reset();
            if (period == null)
            {
                return;
            }

            if (period.EntityState == EntityState.Unchanged)
            {
                this.Load(period.PeriodAllocations);
            }
            else
            {
                using (var dc = Context.GetContextInstance())
                {
                    var p = dc.Periods.SingleOrDefault(item => item.Id == period.Id) ?? period;
                    this.Load(p.PeriodAllocations);
                }
            }

            this.Allocations.UpdateTotal();
        }

        protected override IEnumerable<CommandViewModel> IncludedCommands()
        {
            return
                base.IncludedCommands()
                    .Union(
                        new[] {this.CopyCommand})
                    .ToArray();
        }

        protected override CommandViewModel CreateNewCommand()
        {
            return
                new CommandViewModel(
                    "Add",
                    param => this.DoCreateNew(),
                    param => this.Allocations.CanSave);
        }

        protected override void DoCreateNew()
        {
            var last = this.Allocations.SelectedData;
            var alloc = new PeriodAllocation();
            var curr = this.Allocations.Add(alloc);
            curr.IsSelected = true;
            this.cancelAction =
                () =>
                {
                    this.Load(parent.ActivePeriod);
                    if (last == null)
                    {
                        return;
                    }

                    var selected = (from item in this.Allocations
                                    where item.Data.Id == last.Id
                                    select item).SingleOrDefault();
                    if (selected != null &&
                        !selected.IsSelected)
                    {
                        selected.IsSelected = true;
                    }
                };
            this.DoEdit();
        }

        protected override void DoEdit()
        {
            SetVisibility(Visibility.Collapsed, EditCommand, CopyCommand);
            SetVisibility(Visibility.Visible, SaveCommand, CancelCommand);

            this.Allocations.IsReadOnly = false;
            this.IsInSelectionMode = false;
        }

        protected override void DoDelete()
        {
            if (this.IsInSelectionMode)
            {
                var result = MessageBoxResult.No;
                var message =
                    new DialogMessage(this, "Are you sure?", param => result = param)
                        {
                            Caption = "Confirm Delete Allocation",
                            Button = MessageBoxButton.YesNo,
                            Icon = MessageBoxImage.Question
                        };
                Messenger.Send(message);
                if (result == MessageBoxResult.No)
                {
                    return;
                }
            }

            var todelete = this.Allocations.SelectedItem;
            this.Allocations.Remove(todelete);

            if (this.IsInSelectionMode)
            {
                this.DoSave();
            }
        }

        protected override void DoSave()
        {
            if (this.Allocations.SelectedItem != null)
            {
                this.Allocations.SelectedItem.UpdateContext();
            }

            using (var scope = new TransactionScope())
            using (var dc = Context.GetContextInstance())
            {
                parent.ActivePeriod = dc.Periods.SingleOrDefault(item => item.Id == parent.ActivePeriod.Id) ??
                                      parent.ActivePeriod;
                if (parent.ActivePeriod.EntityState != EntityState.Unchanged)
                {
                    dc.AddToPeriods(parent.ActivePeriod);
                }

                var updated = (from item in this.Allocations
                               where item.Data.Id > 0
                               select item.Data).ToArray();
                var deleted = (from item in parent.ActivePeriod.PeriodAllocations
                               where !updated.Select(u => u.Id).Contains(item.Id)
                               select item).ToArray();
                deleted.ForEach(item => dc.PeriodAllocations.DeleteObject(item));
                foreach (var item in updated)
                {
                    var rec = parent.ActivePeriod.PeriodAllocations.Single(u => u.Id == item.Id);
                    if (rec.ExpenseTypeId != item.ExpenseTypeId)
                    {
                        rec.ExpenseTypeId = item.ExpenseTypeId;
                    }

                    if (!string.Equals(rec.Comment, item.Comment))
                    {
                        rec.Comment = item.Comment;
                    }

                    if (rec.Amount != item.Amount)
                    {
                        rec.Amount = item.Amount;
                    }
                }

                var inserted = (from item in this.Allocations
                                where item.Data.Id == 0
                                select item.Data).ToArray();
                parent.ActivePeriod.PeriodAllocations.AddRange(inserted);
                dc.SaveChanges();
                scope.Complete();
            }

            this.Load(parent.ActivePeriod);
        }

        protected override void DoCancel()
        {
            this.Reset();
            if (this.cancelAction == null)
            {
                this.Load(parent.ActivePeriod);
                return;
            }

            this.cancelAction();
            this.cancelAction = null;
        }

        private CommandViewModel InitializeCopyCommand()
        {
            return this.CopyCommand =
                   new CommandViewModel(
                       "Copy",
                       param => this.CopyPeriodTo(),
                       param => this.parent.ActivePeriod != null &&
                                this.parent.ActivePeriod.Id > 0 &&
                                this.Allocations.Items.Count > 0);
        }

        private PeriodsAllocationListViewViewModel InitializeAllocation()
        {
            var lv = new PeriodsAllocationListViewViewModel();
            return this.Allocations = lv;
        }

        private void Load(IEnumerable<PeriodAllocation> allocations)
        {
            this.Allocations.ClearItems();
            this.Allocations.AddRange(allocations);
        }

        private void Reset()
        {
            this.Allocations.IsReadOnly = true;
            this.IsInSelectionMode = true;
            SetVisibility(Visibility.Visible, NewCommand, EditCommand, DeleteCommand, CopyCommand);
            SetVisibility(Visibility.Collapsed, SaveCommand, CancelCommand);
        }

        private void CopyPeriodTo()
        {
            var dpvm =
                new DatePickerViewModel
                    {
                        Caption = "Month:",
                        Value = DateTime.Now,
                        IsMonthYear = true,
                        DateFormat = "MMMM, yyyy",
                        IsReadOnly = false
                    };

            var rcvm =
                new RadioCollectionViewModel<int>("Period:")
                {
                    ItemSpacing = 5,
                    Orientation = Orientation.Horizontal
                };
            rcvm.Add(1, "[Start - 15]");
            rcvm.Add(16, "[16 - End]");
            if (this.parent.Period.SelectedData == 1)
            {
                rcvm.First().IsChecked = true;
            }
            else
            {
                rcvm.Last().IsChecked = true;
            }

            var vm =
                new FormCollectionViewModel(dpvm, rcvm)
                    {
                        Margin = new Thickness(5),
                        MinWidth = 150,
                        VerticalSpacing = 5
                    };

            var ccvm =
                new CommandCollectionViewModel(
                    new CommandViewModel(
                        "OK",
                        param =>
                        {
                            Messenger.Send(new NotificationMessage(vm, "Close"));
                            this.DoCopy(dpvm.DateValue, rcvm.SelectedData);
                        },
                        param =>
                        !this.parent.ActivePeriod.Start.Equals(
                            new DateTime(dpvm.DateValue.Year, dpvm.DateValue.Month, rcvm.SelectedData))),
                    new CommandViewModel(
                        "Cancel",
                        param => Messenger.Send(new NotificationMessage(vm, "Close"))))
                {
                    CommandsHasSameSizes = true,
                    CommandSpacing = 5,
                    Margin = new Thickness(0, 5, 0, 0),
                    Orientation = Orientation.Horizontal,
                };
            vm.Add(ccvm);

            var msg = new CustomDialogMessage(this, "Select Target Period", vm);
            Messenger.Send(msg);
        }

        private void DoCopy(DateTime month, int startDay)
        {
            var srcPeriodId = this.parent.ActivePeriod.Id;
            this.parent.SetPeriod(new DateTime(month.Year, month.Month, startDay));
            if (parent.ActivePeriod.PeriodAllocations.Count > 0)
            {
                // confirm if it will be overwritten
                var result = MessageBoxResult.No;
                var msg =
                    new DialogMessage(this,
                                      "This period already contains allocations.   Do you wish to overwrite these allocations?",
                                      param => result = param)
                        {
                            Button = MessageBoxButton.YesNo,
                            Caption = "Confirm Allocation Overwrite",
                            Icon = MessageBoxImage.Question
                        };
                Messenger.Send(msg);
                if (result == MessageBoxResult.No)
                {
                    return;
                }
            }

            this.Allocations.ClearItems();
            using (var dc = Context.GetContextInstance())
            {
                var src = dc.Periods.Single(item => item.Id == srcPeriodId);
                foreach (var item in src.PeriodAllocations)
                {
                    this.Allocations.Add(
                        new PeriodAllocation
                            {
                                ExpenseType = item.ExpenseType,
                                ExpenseTypeId = item.ExpenseTypeId,
                                Comment = item.Comment,
                                Amount = item.Amount
                            });
                }
            }

            this.cancelAction = () => this.Load(parent.ActivePeriod);
            this.DoEdit();
        }

        #endregion Methods
    }
}
